package org.aeon.client.view.components.sessionPanel;

import lombok.Setter;
import org.aeon.client.context.GlobalContext;
import org.aeon.constant.BiasDirection;
import org.aeon.constant.MessageSendStatus;
import org.aeon.entity.ChatMessage;
import org.aeon.entity.User;
import org.aeon.entity.dto.GroupInfoDto;
import org.aeon.entity.dto.UserInfoDto;
import org.aeon.service.UserMessageService;
import org.aeon.utils.NewScrollBarUI;

import javax.swing.*;
import java.awt.*;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

import static java.awt.GridBagConstraints.*;
import static org.aeon.constant.MessageSendStatus.NORMAL;
import static org.aeon.constant.MessageSendStatus.SEND_FAILED;

/**
 * @author: MissingAeon
 * @date: 2024/2/20 19:10
 * @description:
 */
public class ChatRecordPanel extends JScrollPane {
    private JPanel panel;
    private GridBagConstraints gbc;
    private UserInfoDto user;
    private GroupInfoDto group;
    private Long start;
    private AtomicBoolean complete;
    @Setter
    private ChatEditorPanel editorPanel;

    public ChatRecordPanel(Dimension preferredSize) {
        // this.setUI(new NewScrollPaneUI());

        this.setPreferredSize(preferredSize);
        this.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        this.setHorizontalScrollBar(null);
        this.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        this.setBorder(null);


        // this.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));

        initialization();
    }

    private void initialization() {
        JScrollBar bar = this.getVerticalScrollBar();
        bar.setUnitIncrement(10);
        bar.setUI(new NewScrollBarUI());

        complete = new AtomicBoolean(true);

        panel = new JPanel();
        panel.setLayout(new GridBagLayout());
        panel.setOpaque(false);

        gbc = new GridBagConstraints();

        gbc.gridx = 0;
        gbc.gridy = RELATIVE;
        gbc.weightx = 1;
        gbc.fill = NONE;

        final Box box = Box.createVerticalBox();
        box.setBackground(new Color(181, 189, 187, 74));
        box.setOpaque(true);
        box.add(panel);

        box.add(Box.createVerticalGlue());
        this.setViewportView(box);
    }

    public void load(UserInfoDto user) {
        this.user = user;

        initialization();

        final UserMessageService service = UserMessageService.service;
        final GlobalContext context = GlobalContext.getContext();

        final User currentUser = context.getCurrentUser();

        // 获取消息
        List<ChatMessage> chatMessages = service.readMessagesByTime(currentUser.getId(), user.getId(), new Date());
        if (chatMessages.isEmpty()) {
            chatMessages = service.readMessagesByTimeToRange(currentUser.getId(), user.getId(), null, 5);
            if (chatMessages.isEmpty()) {
                start = -1L;
                return;
            }
            start = chatMessages.get(0).getCreationTime();
        }
        load0(currentUser, chatMessages);

        // bar.addAdjustmentListener(e -> {
        //
        //     // 运行完毕
        //     if (!complete.get()) return;
        //     // 到顶部
        //     if (e.getValue() != bar.getMinimum()) return;
        //     // 还有数据
        //     if ((start == null ? 0 : start) < 0) return;
        //
        //     complete.set(false);
        //
        //     context.getThreadPool().execute(() -> {
        //         // 懒加载
        //         final List<UserMessage> list = service.readMessagesByTimeToRange(
        //                 currentUser.getId(), user.getId(), start, 5);
        //         if (list.isEmpty()) {
        //             start = -1L;
        //             return;
        //         }
        //         start = list.get(0).getCreationTime();
        //         try {
        //             SwingUtilities.invokeAndWait(() -> {
        //                 final int mum = bar.getMaximum();
        //                 load0(currentUser, list);
        //                 bar.setValue(bar.getMaximum() - mum);
        //             });
        //             Thread.sleep(50);
        //         } catch (InterruptedException | InvocationTargetException ignored) {
        //         }
        //         complete.set(true);
        //     });
        //
        // });
    }

    public void load(GroupInfoDto group) {
        this.group = group;
        initialization();

        final UserMessageService service = UserMessageService.service;
        final GlobalContext context = GlobalContext.getContext();

        final User currentUser = context.getCurrentUser();

        // 获取消息
        List<ChatMessage> chatMessages = service.readMessagesByTime(currentUser.getId(), -group.getId(), new Date());
        if (chatMessages.isEmpty()) {
            chatMessages = service.readMessagesByTimeToRange(currentUser.getId(), -group.getId(), null, 5);
            if (chatMessages.isEmpty()) {
                start = -1L;
                return;
            }
            start = chatMessages.get(0).getCreationTime();
        }
        load0(currentUser, chatMessages);

    }

    private void load0(User currentUser, List<ChatMessage> list) {
        final GridBagLayout bagLayout = (GridBagLayout) panel.getLayout();
        final LinkedHashMap<Component, GridBagConstraints> componentsAndStyles =
                Arrays.stream(panel.getComponents()).collect(Collectors.toMap(component -> component,
                        bagLayout::getConstraints, (k1, k2) -> k2, LinkedHashMap::new));
        // 初始化消息
        list.forEach(message -> {
            BiasDirection direction;
            if (message.getFrom() == currentUser.getId() || message.getFrom() == 0) {
                direction = BiasDirection.RIGHT;
                gbc.insets = new Insets(10, 20, 10, 20);
                gbc.anchor = LINE_END;
            } else {
                direction = BiasDirection.LEFT;
                gbc.insets = new Insets(10, 20, 10, 20);
                gbc.anchor = LINE_START;
            }

            // 如果From为0 显示发送失败警告，否则正常显示
            final ChatRecordItem item = new ChatRecordItem(direction, message.getFrom() == 0 ? SEND_FAILED : NORMAL);
            panel.add(item, gbc);

            if (user != null) item.load(user, message);
            else if (group != null) item.load(group, message);
        });
        if (!list.isEmpty())
            // 记录查询位置
            start = list.get(0).getCreationTime();

        componentsAndStyles.forEach((k, v) -> panel.add(k, v));

        final Dimension dimension = new Dimension(Integer.MAX_VALUE, panel.getMinimumSize().height);
        panel.setMaximumSize(dimension);
        panel.repaint();
    }

    /**
     * 添加一条新消息
     *
     * @param message
     * @param sendStatus
     * @return
     */
    public ChatRecordItem newNews(ChatMessage message, MessageSendStatus sendStatus) {
        // 初始化消息
        BiasDirection direction;
        if (message.getFrom() == GlobalContext.getContext().getCurrentUser().getId() || message.getFrom() == 0) {
            direction = BiasDirection.RIGHT;
            gbc.insets = new Insets(10, 20, 10, 20);
            gbc.anchor = LINE_END;
        } else {
            direction = BiasDirection.LEFT;
            gbc.insets = new Insets(10, 20, 10, 20);
            gbc.anchor = LINE_START;
        }
        // 添加消息
        final ChatRecordItem item = new ChatRecordItem(direction, sendStatus);
        panel.add(item, gbc);

        if (user != null) item.load(user, message);
        else if (group != null) item.load(group, message);

        final Dimension dimension = new Dimension(Integer.MAX_VALUE, panel.getMinimumSize().height);
        panel.setMaximumSize(dimension);
        panel.repaint();

        return item;
    }

    /**
     * 修改滑块位置
     *
     * @param barValue
     */
    public void setScrollBar(int barValue) {
        SwingUtilities.invokeLater(() -> {
            final JScrollBar bar = this.getVerticalScrollBar();
            if (barValue < 0) {
                if (panel.getComponents().length != 0
                        && bar.getMaximum() == 0) {
                    this.setScrollBar(barValue);
                    return;
                }
                bar.setValue(bar.getMaximum());
            } else bar.setValue(barValue);
            repaint();
        });
    }

}
